home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / The Hacks / Avi's Balloon Previewer / ShowInitIcon.c < prev   
Encoding:
C/C++ Source or Header  |  1999-06-24  |  8.1 KB  |  271 lines  |  [TEXT/CWIE]

  1. #include <Icons.h>
  2. // #include <IconUtilsPriv.h>
  3. #include <Resources.h>
  4. #include <Gestalt.h>
  5. #include <Sound.h>
  6. #include <TextUtils.h>
  7.  
  8. #define    IconRef    Handle
  9.  
  10. /*
  11.     ShowInitIcon.c
  12.     ShowINIT compatible routine that shows 'iclx' and 'icns' icons.
  13.     For use by all INITs in System 7.0 and beyond.
  14.     Requires OS 7.0 and up.
  15.     
  16.     4/7/99
  17.     Modified by Bruce Partridge to handle Icon Services icns resources.    
  18.     Also fixed for PowerPC data alignment, and removed support for
  19.     pre Color Quickdraw systems.  Now runs either as 68K or PowerPC.
  20.     Send comments/bugs to: Bruce Partridge at <bpart1@aol.com> or <halfhill@kagi.com>
  21.     
  22.  
  23.     This code was written or modified by Paul Mercer, Darin Adler, Paul Snively,
  24.     Steve Capps, Patrick C. Beard, Peter N Lewis, François Pottier, and Jim W Walker.
  25.  
  26.     This code is in the public domain.
  27.  
  28.     Instructions for use:
  29.     
  30.         ••• You must include IconServicesLib to compile this as PowerPC code
  31.         ••• BE SURE TO WEAK LINK THE LIBRARY or you will get an endless and
  32.         ••• baffling series of crashes when Icon Services is not present
  33.         ••• ie OS < 8.5 .
  34.         
  35.         • Create a family of icons with ResEdit 2.1 or later.  This will
  36.             include 'ICN#', 'icl4', & 'icl8' icons, all with the
  37.             same resource ID.
  38.         • Optionally create an icns with the same resource ID for use with
  39.             OS 8.5 and up.  If your INIT is going to display an icon on OS
  40.             < 8.5 you must supply the icon family as well.
  41.         
  42.         To use within a larger INIT project:
  43.             • #define SEPARATE_CODE 0  below.
  44.             • Call ShowInitIcon( id, adv ) with the resource id of
  45.                 the family that you used.  The Boolean parameter adv
  46.                 indicates whether you want the next use of ShowInitIcon
  47.                 to advance to a new position.  Normally you pass TRUE,
  48.                 but you can get an animated-icon effect by passing FALSE
  49.                 all except the last time you call ShowInitIcon.
  50.         
  51.         To use as a separate code resource:
  52.             • #define SEPARATE_CODE 1  below.
  53.             • Set the project type to code resource, set the code type
  54.                 and resource ID (I use type 'Code', ID -4048 for cdevs),
  55.                 compile and merge into your INIT or cdev file.
  56.                 Set the resource type to Locked, so you won't have
  57.                 to call HLock when you use it.
  58.             • In your main INIT code, call ShowInitIcon like so:
  59.                 pascal void (*ShowInitIcon)( short resid, Boolean adv );
  60.                 Handle  show_init;
  61.                 
  62.                 show_init = GetResource( 'Code', -4048 );
  63.                 ShowInitIcon = (pascal void (*)(short, Boolean))
  64.                             StripAddress( *show_init );
  65.                 ShowInitIcon( iconID, advance );
  66.  */
  67.  
  68. #define SEPARATE_CODE    0
  69.  
  70.  
  71. #if SEPARATE_CODE
  72. #define        ShowInitIcon        main
  73. #endif
  74.  
  75. #ifndef nil
  76. #define nil ((void*)0L)
  77. #endif
  78.  
  79. #ifndef topLeft
  80.     #define topLeft(r) ((Point*)&r)[0])
  81. #endif
  82. #ifndef botRight
  83.     #define botRight(r) ((Point*)&r)[1])
  84. #endif
  85.  
  86. // Alignment here must be 68K, or screenbits.bounds address will be off by
  87. // padding and GetIconRect will return incorrect values. BP
  88. // #pragma options align=mac68k
  89. typedef struct myQDGlobals {
  90.     char privates[76];
  91.     long randSeed;
  92.     BitMap screenBits;
  93.     Cursor arrow;
  94.     Pattern dkGray;
  95.     Pattern ltGray;
  96.     Pattern gray;
  97.     Pattern black;
  98.     Pattern white;
  99.     GrafPtr thePort;
  100.     long    end;
  101. } myQDGlobals;
  102. // #pragma options align=reset
  103.  
  104. /* prototypes */
  105. pascal void ShowInitIcon(short iconId, Boolean advance);
  106. static void Next_position( void );
  107. static void GetIconRect( register Rect* iconRect, Rect *screen_rect );
  108. OSErr GetSelfFSSpec(FSSpec* theFSSpec);
  109.  
  110. /*
  111. //-------------------------------------
  112. main(void)    // For testing purposes only
  113. {
  114.     int iconId = 128;
  115.     unsigned long finalTick;
  116.  
  117.     ShowInitIcon(iconId,true);
  118.     Delay(200,&finalTick);
  119.  
  120.     return (0);
  121. }
  122. //-------------------------------------
  123. */
  124.  
  125. /* this is where it all happens. */
  126. pascal void ShowInitIcon( short iconId, Boolean advance)
  127. {
  128.     long    oldA5;
  129.     myQDGlobals qd;                /* our QD globals. */
  130.     CGrafPort gp;                /* our grafport. */
  131.     Rect    icon_rect;
  132.     OSErr theErr;
  133.     FSSpec theFSSpec;
  134.     IconRef iconRef;
  135.     long gestaltval;
  136.     OSType fakecreator = 'MMac';    // anything will do here
  137.     OSType faketype = 'OS85';        // for Icon Services calls
  138.     
  139.     // Do we have Color QuickDraw etc ?
  140.     Gestalt(gestaltSystemVersion,&gestaltval);
  141.     if(gestaltval < 0x700)
  142.         return;    
  143.  
  144.     /* get a value for A5, a structure that mirrors qd globals. */
  145.     oldA5 = SetA5((long)&qd.end);
  146.     InitGraf(&qd.thePort);
  147.     
  148.     GetIconRect( &icon_rect, &(qd.screenBits.bounds) );
  149.     OpenCPort(&gp);
  150.     
  151.     // test for Icon Services icns handling
  152.     Gestalt(gestaltIconUtilitiesAttr,&gestaltval);
  153.     if(false /* gestaltval & gestaltIconUtilitiesHasIconServices */)
  154.     {
  155.         // Icon Services will preferentially load icns over iclx of the same ID
  156.         // If there's no icns, it'll load the iclx
  157.         theErr = GetSelfFSSpec(&theFSSpec);
  158.         if(theErr == noErr)
  159.             theErr = 0;    // RegisterIconRefFromResource (fakecreator,faketype,&theFSSpec,iconId,&iconRef);
  160.         if(theErr == noErr)
  161.         {
  162.             theErr = 0;    // PlotIconRef(&icon_rect,kAlignAbsoluteCenter,nil,kIconServicesNormalUsageFlag,iconRef);
  163.             theErr = 0;    // UnregisterIconRef (fakecreator,faketype);
  164.         }
  165.     }    
  166.     else
  167.         theErr = PlotIconID( &icon_rect, atNone, ttNone, iconId );
  168.     CloseCPort(&gp);
  169.  
  170.     if (advance)
  171.         Next_position(); /* JWW */
  172.  
  173.     SetA5(oldA5);
  174. }
  175.  
  176. /*
  177.     ShowInit's information is nestled at the tail end of CurApName.
  178.     It consists of a short which encodes the next horizontal offset,
  179.     and another short which is that value checksummed with the function below.
  180.  */
  181.  
  182. #define CurApName_LM    0x910
  183. #define ShowINITTable ((unsigned short*)(CurApName_LM + 32 - 4))
  184. #define CheckSumConst 0x1021        /* magic value to check-sum with. */
  185.  
  186. #define InitialXPosition 8            /* initial horizontal offset. */
  187. #define YOffset            40            /* constant from bottom to place the icon. */
  188. #define XOffset            40            /* amount to change it by. */
  189. #define ICON_WIDTH        32
  190. #define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
  191.  
  192. /* CheckSum() computes the magic value to determine if ShowInit's have run already. */
  193.  
  194. static short CheckSum(register unsigned short x)
  195. {
  196.     if (x & 0x8000)    /* high bit set */
  197.         return((x << 1) ^ CheckSumConst ^ 0x01);
  198.     else
  199.         return ((x << 1) ^ CheckSumConst);
  200. }
  201.  
  202. /*
  203.     GetIconRect() generates an appropriate rectangle to display the
  204.     next INIT's icon in.
  205.     It is also responsible for updating the horizontal
  206.     position in low memory.  This is a departure from
  207.     the original ShowInit code, which updates low
  208.     memory AFTER displaying the icon. -- changed by JWW
  209.     This code won't generate an icon position until it is certain that the icon can be loaded,
  210.     so the same behaviour occurs.
  211.     
  212.     This routine also generates a rectangle which is guaranteed to be onscreen.  It
  213.     does this by taking the horizontal offset modulo the screen width to generate
  214.     the horizontal position of the icon, and the offset divided by the screen
  215.     width to generate the proper row.
  216.  */
  217.  
  218. static void GetIconRect(register Rect* iconRect, Rect *screen_rect )
  219. {
  220.     register short screenWidth;
  221.     screenWidth = screen_rect->right - screen_rect->left;
  222.     screenWidth -= screenWidth % XOffset;
  223.     /* if we are the first INIT to run we need to initialize the horizontal value. */
  224.     if (CheckSum(ShowINITTable[0]) != ShowINITTable[1])
  225.         ShowINITTable[0] = InitialXPosition;
  226.     
  227.     /* compute top left of icon's rect. */
  228.     iconRect->left = (ShowINITTable[0] % screenWidth);
  229.     iconRect->top = screen_rect->bottom -
  230.         YOffset * (1 + (ShowINITTable[0] / screenWidth));
  231.     iconRect->right = iconRect->left + 32;
  232.     iconRect->bottom = iconRect->top + 32;
  233.     
  234. }
  235.  
  236. /*
  237.     JWW: In Beard's original version, this was done at the end of
  238.     GetIconRect. That caused incorrect behavior when IconWrap 1.2 was
  239.     used to wrap icons.  Namely, if an INIT using that version of
  240.     ShowIconFamily was the first in a row, then the second icon in that
  241.     row would land on top of it.
  242. */
  243. static void Next_position( void )
  244. {
  245.     /* advance the position for the next icon. */
  246.     ShowINITTable[0] += XOffset;
  247.     
  248.     /* recompute the checksum. */
  249.     ShowINITTable[1] = CheckSum(ShowINITTable[0]);    
  250. }
  251.  
  252.  
  253. OSErr GetSelfFSSpec(FSSpec* theFSSpec)
  254. {
  255.     OSErr        theErr;
  256.     Str255        procname;
  257.     FCBPBRec    fcbPB;
  258.     // The FSSpec is needed to get an IconRef with Icon Services
  259.     // Process Manager isn't loaded yet so use PB calls BP 4/99
  260.     fcbPB.ioNamePtr = procname;
  261.     fcbPB.ioVRefNum = 0;
  262.     fcbPB.ioRefNum = CurResFile();
  263.     fcbPB.ioFCBIndx = 0;
  264.     theErr = PBGetFCBInfoSync(&fcbPB);
  265.     
  266.     if(theErr == noErr)
  267.         theErr = FSMakeFSSpec(fcbPB.ioVRefNum,fcbPB.ioFCBParID,procname,theFSSpec);
  268.     return theErr;
  269. }
  270.  
  271.